import path from "path";
import { fileURLToPath } from "url";
import test from "tape";
import { glob } from "glob";
import { loadJsonFileSync } from "load-json-file";
import { writeJsonFileSync } from "write-json-file";
import { featureCollection, polygon } from "@turf/helpers";
import { difference } from "./index.js";

const __dirname = path.dirname(fileURLToPath(import.meta.url));

const directories = {
  in: path.join(__dirname, "test", "in") + path.sep,
  out: path.join(__dirname, "test", "out") + path.sep,
};

test("turf-difference", (t) => {
  glob.sync(directories.in + "*.geojson").forEach((filepath) => {
    const { name, base } = path.parse(filepath);
    const [polygon1, polygon2] = loadJsonFileSync(filepath).features;

    if (name.includes("skip")) return t.skip(name);

    // Red Polygon1
    polygon1.properties = Object.assign(polygon1.properties || {}, {
      "fill-opacity": 0.5,
      fill: "#F00",
    });
    // Blue Polygon2
    polygon2.properties = Object.assign(polygon2.properties || {}, {
      "fill-opacity": 0.5,
      fill: "#00F",
    });

    const results = featureCollection([polygon1, polygon2]);

    const result = difference(results);
    if (result) {
      // Green Polygon
      result.properties = { "fill-opacity": 1, fill: "#0F0" };
      results.features.push(result);
    }

    if (process.env.REGEN) writeJsonFileSync(directories.out + base, results);
    t.deepEqual(results, loadJsonFileSync(directories.out + base), name);
  });
  t.end();
});

test("turf-difference - support specific polygons", (t) => {
  const poly1 = polygon([
    [
      [121, -31],
      [144, -31],
      [144, -15],
      [121, -15],
      [121, -31],
    ],
  ]);
  const poly2 = polygon([
    [
      [126, -28],
      [140, -28],
      [140, -20],
      [126, -20],
      [126, -28],
    ],
  ]);

  t.assert(
    difference(featureCollection([poly1, poly2])),
    "geometry object support"
  );
  t.end();
});

test("turf-difference - prevent input mutation", (t) => {
  const poly1 = polygon([
    [
      [121, -31],
      [144, -31],
      [144, -15],
      [121, -15],
      [121, -31],
    ],
  ]);
  const poly2 = polygon([
    [
      [126, -28],
      [140, -28],
      [140, -20],
      [126, -20],
      [126, -28],
    ],
  ]);
  const before1 = JSON.parse(JSON.stringify(poly1));
  const before2 = JSON.parse(JSON.stringify(poly2));

  difference(featureCollection([poly1, poly2]));
  t.deepEqual(poly1, before1, "polygon1 should not mutate");
  t.deepEqual(poly2, before2, "polygon2 should not mutate");
  t.end();
});

test("turf-difference - complete overlap", (t) => {
  const poly = polygon([
    [
      [121, -31],
      [144, -31],
      [144, -15],
      [121, -15],
      [121, -31],
    ],
  ]);

  const result = difference(featureCollection([poly, poly]));
  t.deepEqual(result, null, "difference should be null");
  t.end();
});

test("difference - unable to complete output ring - issue 2409", (t) => {
  // Test examples copied from https://github.com/Turfjs/turf/issues/2409
  const area1 = polygon([
    [
      [11.79926, 59.307999],
      [18.80383, 60.15596],
      [18.73765340635914, 60.23951348693759],
      [18.58133, 60.34301],
      [11.79926, 59.307999],
    ],
  ]);

  const area1_subtract = polygon([
    [
      [11.79926, 59.307999],
      [18.80383, 60.15596],
      [
        18.73765340635913, // Subtract 1 to final digit
        60.23951348693759,
      ],
      [18.58133, 60.34301],
      [11.79926, 59.307999],
    ],
  ]);

  const area1_add = polygon([
    [
      [11.79926, 59.307999],
      [18.80383, 60.15596],
      [
        18.73765340635915, // Add 1 to final digit
        60.23951348693759,
      ],
      [18.58133, 60.34301],
      [11.79926, 59.307999],
    ],
  ]);

  const area2 = polygon([
    [
      [18.35554, 60.35768],
      [18.58133, 60.34301],
      [18.75959, 60.22499],
      [18.80383, 60.15596],
      [18.35554, 60.35768],
    ],
  ]);

  t.doesNotThrow(
    () => difference(featureCollection([area1, area2])),
    "[area1, area2] should not throw"
  );
  t.doesNotThrow(
    () => difference(featureCollection([area1_subtract, area2])),
    "[area1_subtract, area2] should not throw"
  );
  t.doesNotThrow(
    () => difference(featureCollection([area1_add, area2])),
    "[area1_add, area2] should not throw"
  );

  t.end();
});

test("difference - unable to complete output ring - issue 2277", (t) => {
  // Test example copied from https://github.com/Turfjs/turf/issues/2277
  const poly1 = polygon([
    [
      [54.56658645236534, 24.445194105819738],
      [54.56658654953498, 24.441605817571325],
      [54.57000000000001, 24.43981171174874],
      [54.57341345046501, 24.441605817571325],
      [54.573413547634665, 24.445194105819738],
      [54.57000000000001, 24.44698828825126],
      [54.56658645236534, 24.445194105819738],
    ],
    [
      [54.56795530519258, 24.44447467409078],
      [54.57000000000001, 24.4455493756693],
      [54.57204469480743, 24.44447467409078],
      [54.57204465994316, 24.442325298422087],
      [54.57000000000001, 24.441250624330703],
      [54.56795534005685, 24.442325298422087],
      [54.56795530519258, 24.44447467409078],
    ],
  ]);

  const poly2 = polygon([
    [
      [54.569778932416476, 24.441366817541834],
      [54.56977894449294, 24.441074136738756],
      [54.57000000000001, 24.441190327160086],
      [54.57084694057397, 24.440745161222193],
      [54.57084693745136, 24.44028034081218],
      [54.571147760242575, 24.44043845608456],
      [54.57114771720956, 24.441853864959285],
      [54.57080496898934, 24.4416737163564],
      [54.57080502276297, 24.441026402022757],
      [54.57074511559248, 24.441057889217532],
      [54.57074509421786, 24.441642246152345],
      [54.57000000000001, 24.441250624330703],
      [54.569778932416476, 24.441366817541834],
    ],
  ]);

  t.doesNotThrow(
    () => difference(featureCollection([poly1, poly2])),
    "[poly1, poly2] should not throw"
  );

  t.end();
});

test("difference - maximum call stack size exceeded - issue 2479", (t) => {
  // Test example copied from https://github.com/Turfjs/turf/issues/2479
  const poly1 = polygon([
    [
      [49.93317115095019, 20.170898437500004],
      [49.93927561914192, 20.16278743743897],
      [49.941126142253154, 20.165448188781742],
      [49.934096538617936, 20.174009799957275],
      [49.93317115095019, 20.170898437500004],
    ],
  ]);

  const poly2 = polygon([
    [
      [49.93317115095019, 20.170898437500004],
      [49.933680058500165, 20.170222252607346],
      [49.933758735535065, 20.170222252607346],
      [49.933803934349285, 20.170152112841606],
      [49.933803934349285, 20.170057658905122],
      [49.934306839656294, 20.169389449185992],
      [49.93434632011994, 20.16945071518421],
      [49.93434632011994, 20.16959099471569],
      [49.93448191656261, 20.16980141401291],
      [49.93457231419105, 20.16980141401291],
      [49.93466271181949, 20.16966113448143],
      [49.93484350707638, 20.16966113448143],
      [49.93520509759015, 20.169100016355515],
      [49.93529549521859, 20.169100016355515],
      [49.935928278617695, 20.168118059635166],
      [49.936018676246135, 20.168118059635166],
      [49.93660626083101, 20.167206242680553],
      [49.93660626083101, 20.167065963149074],
      [49.9367870560879, 20.166785404086117],
      [49.9367870560879, 20.166645124554638],
      [49.93714864660167, 20.166084006428722],
      [49.93714864660167, 20.165613543475054],
      [49.93742361679489, 20.16524819088677],
      [49.93755543592966, 20.165452748537067],
      [49.938504611028314, 20.16397981345654],
      [49.938504611028314, 20.163811875057462],
      [49.93927561914192, 20.16278743743897],
      [49.941126142253154, 20.165448188781742],
      [49.93988364085967, 20.16696147663808],
      [49.93981537664073, 20.166855543851856],
      [49.93958938256963, 20.167206242680553],
      [49.93958938256963, 20.167319864563666],
      [49.934096538617936, 20.174009799957275],
      [49.93317115095019, 20.170898437500004],
    ],
  ]);

  t.doesNotThrow(
    () => difference(featureCollection([poly1, poly2])),
    "[poly1, poly2] should not throw"
  );

  t.end();
});

test("difference - unable to find segment - issue 2306", (t) => {
  // Test example copied from https://github.com/Turfjs/turf/issues/2306
  const poly1 = polygon([
    [
      [10.299138347373786, 48.460352133145804],
      [10.299142854373908, 48.46034913552448],
      [10.299142854373908, 48.460339214732976],
      [10.299225267807545, 48.46033958029495],
      [10.29927355737747, 48.46034017606536],
      [10.29927355737747, 48.46034613790316],
      [10.299266796877285, 48.46035363195647],
      [10.299257782877039, 48.46035363195647],
      [10.299251022376856, 48.46035812838846],
      [10.299251022376856, 48.46036507625937],
      [10.299195961284822, 48.4603647734974],
      [10.299201445375504, 48.46036112600978],
      [10.29919468487532, 48.460356629577795],
      [10.299187924375136, 48.46035812838846],
      [10.299187924375136, 48.46036112600978],
      [10.299193387184792, 48.460364759343314],
      [10.299138347373786, 48.460364456698365],
      [10.299138347373786, 48.460352133145804],
    ],
    [
      [10.299142854373908, 48.46035812838846],
      [10.299145107873969, 48.46035962719912],
      [10.2991608823744, 48.46035812838846],
      [10.299158628874338, 48.46035363195647],
      [10.299149614874093, 48.46035363195647],
      [10.299142854373908, 48.46035812838846],
    ],
  ]);

  const poly2 = polygon([
    [
      [10.299138347373786, 48.46036049139952],
      [10.299187924375136, 48.46036028454162],
      [10.299187924375136, 48.46036112600978],
      [10.29919468487532, 48.46036562244176],
      [10.299201445375504, 48.46036112600978],
      [10.299200103800315, 48.46036023372349],
      [10.299208777179729, 48.46036019753419],
      [10.299209806197382, 48.46031596598246],
      [10.299250947482829, 48.460316111877646],
      [10.299251022376856, 48.460316161689924],
      [10.299251022376856, 48.46031915931125],
      [10.299257677970186, 48.46032358596932],
      [10.299256707063519, 48.46035434748375],
      [10.299251022376856, 48.46035812838846],
      [10.299251022376856, 48.4603761141164],
      [10.299246515376732, 48.46037911173772],
      [10.299246515376732, 48.4603872476338],
      [10.29919425093356, 48.460374326689575],
      [10.299190177875197, 48.460371617684416],
      [10.299188312254989, 48.46037285851485],
      [10.299138347373786, 48.460360506074],
      [10.299138347373786, 48.46036049139952],
    ],
  ]);

  t.doesNotThrow(
    () => difference(featureCollection([poly1, poly2])),
    "[poly1, poly2] should not throw"
  );

  t.end();
});
